﻿using System;
using System.Net;
using System.Web;
using System.Web.Hosting;
using System.Threading;
using System.Diagnostics;

//自定义命名空间
using DreamCube.Framework.Utilities.Log;
using DreamCube.Foundation.Basic.Extensions.System;

namespace DreamCube.Apps.WinForm.Common.DotNetWebServer
{
    public class AspNetServer
    {
        #region "字段"

        /// <summary>
        /// 监听Http请求的监听对象
        /// </summary>
        private HttpListener listener = null;

        /// <summary>
        /// 监听的前缀
        /// </summary>
        private String[] prefix = null;

        #endregion

        #region "属性"

        /// <summary>
        /// 获取服务器监听的url前缀
        /// </summary>
        public String[] Prefix
        {
            get
            {
                return this.prefix;
            }
        }

        /// <summary>
        /// 请求对应的物理路径
        /// </summary>
        public String PhysicalPath
        {
            get;
            set;
        }

        /// <summary>
        /// 请求的虚拟目录
        /// </summary>
        public String VirtualPath
        {
            get;
            set;
        }

        /// <summary>
        /// 默认文档列表
        /// </summary>
        public String[] DefaultDocuments
        {
            get;
            set;
        }

        /// <summary>
        /// 限制访问的目录
        /// </summary>
        public String[] RestrictedPaths
        {
            get;
            set;
        }

        #endregion

        #region "事件"

        /// <summary>
        /// 获取到请求上下文时回调的事件
        /// </summary>
        public event Action<HttpListenerContext> ReceiveContext;

        #endregion

        #region "实例方法"

        /// <summary>
        /// 创建一个AspNet服务器
        /// </summary>
        /// <param name="prefix">服务器监听的Url前缀</param>
        /// <param name="virtualPath">虚拟路径</param>
        /// <param name="physicalPath">物理路径</param>
        /// <param name="defaultDocuments">默认文档</param>
        /// <param name="restrictedPaths">受限制的文档</param>
        public AspNetServer(String[] prefix, String virtualPath, String physicalPath, 
                                String[] defaultDocuments, String[] restrictedPaths)
        {
            if (String.IsNullOrEmpty(physicalPath))
                throw new ArgumentException(String.Format(Properties.Resources.ExceptionParameterNullOrEmpty, "physicalPath"));

            this.prefix = prefix;
            this.PhysicalPath = physicalPath;
            this.VirtualPath = virtualPath.IsNullOrEmpty() ? "/" : virtualPath;
            this.DefaultDocuments = defaultDocuments == null ? Utility.GetDefualtDocuments() : defaultDocuments;
            this.RestrictedPaths = restrictedPaths == null ? Utility.GetDefaultRestrictedDirs() : restrictedPaths;

            this.InitialHttpListener();
        }

        /// <summary>
        /// 启动服务器
        /// </summary>
        public void Start()
        {
            try
            {
                if (this.listener != null)
                {
                    if (!this.listener.IsListening)
                        this.listener.Start();
                    this.StartGetRequest();
                }
            }
            catch (Exception ex)
            {
                LoggerManager.Logger.MakeLogAsync(ex);
            }
        }

        /// <summary>
        /// 关闭服务器
        /// </summary>
        public void Stop()
        {
            try
            {
                if (this.listener != null && this.listener.IsListening)
                    this.listener.Stop();
                Process.GetCurrentProcess().Kill();
            }
            catch (Exception ex)
            {
                LoggerManager.Logger.MakeLogAsync(ex);
            }
        }

        #endregion

        #region "私有方法"

        /// <summary>
        /// 初始化httplistener对象
        /// </summary>
        private void InitialHttpListener()
        {
            this.listener = new HttpListener();
            Int32 length = this.Prefix.Length;
            for (Int32 i = 0; i < length; i++)
                this.listener.Prefixes.Add(this.Prefix[i]);
        }

        /// <summary>
        /// 开始接收请求
        /// </summary>
        private void StartGetRequest()
        {
            try
            {
                if (this.listener != null)
                    this.listener.BeginGetContext(EndGetRequest, null);
            }
            catch (Exception ex)
            {
                LoggerManager.Logger.MakeLogAsync(ex);
            }
        }

        /// <summary>
        /// 接收到http请求回调的方法
        /// </summary>
        /// <param name="result"></param>
        private void EndGetRequest(IAsyncResult result)
        {
            try
            {
                HttpListenerContext context = this.listener.EndGetContext(result);
                this.StartGetRequest();
                if (ReceiveContext != null)
                    ReceiveContext.BeginInvoke(context, null, null);
                else
                    DoProcessRequest(context);
            }
            catch (Exception ex)
            {
                LoggerManager.Logger.MakeLogAsync(ex);
            }
        }

        /// <summary>
        /// 处理Http请求的方法
        /// </summary>
        /// <param name="context"></param>
        private void DoProcessRequest(HttpListenerContext context)
        {
            try
            {
                if (!Utility.ValidateRequestUrl(context))
                    return;
               
                AspNetRequest request = new AspNetRequest(context, this);
                ThreadPool.QueueUserWorkItem((obj) => { HttpRuntime.ProcessRequest(request); });
            }
            catch (Exception ex)
            {
                LoggerManager.Logger.MakeLogAsync(ex);
            }
        }

        #endregion
    }
}
